5.4 Gshare
分支方向预测器
分支方向预测器用于产生条件分支指令的方向(执行或不执行)预测。它位于处理器流水线前端,负责指导指令获取沿着(期望中的)正确的程序执行路径进行。分支方向预测器通常与分支目标缓冲区(BTB)一起使用,其中BTB预测目标地址,而方向预测器决定是跳转到目标地址还是沿直通路径继续获取指令。
在流水线的稍后阶段(通常在分支执行或退役时),执行过的分支指令的结果会反馈给分支预测器,通过观察过去的分支行为来训练预测器,以便将来能更准确地预测。当出现分支预测失误时,也可能会发生流水线冲洗。
本次练习中,假设分支方向预测器位于右侧图表所示的假设处理器流水线的取指阶段。本练习仅构建分支方向预测器,如图表中蓝色虚线矩形所示。
分支方向预测是组合逻辑路径:使用pc寄存器计算出执行/不执行预测,这影响了下一个周期pc值的确定。
相反,模式历史表(PHT)和分支历史寄存器的更新在下一个时钟正边沿生效,正如存储在触发器中的状态所预期的那样。
分支方向预测器位于处理器流水线的取指(Fetch)阶段。该预测器利用当前的程序计数器(pc)和历史寄存器来做出预测,预测的结果会影响到下一个周期中的程序计数器值。分支的训练请求和预测失误通知来自于流水线的后续阶段。
Gshare预测器
分支方向预测器常被设计为由程序计数器和分支历史索引的计数器表格。表索引是分支地址和历史的哈希值,试图为每种分支和历史组合提供自己的表项(或者至少减 少冲突数量)。每个表项包含一个两位饱和计数器,用于记住过去相同分支和历史模式执行时的分支方向。
这种风格预测器的一个例子是gshare预测器[1]。在gshare算法中,分支地址(pc)和历史位“共享”表索引位。基本的gshare算法通过异或N位分支地址位和N位全局分支历史位来计算N位PHT表索引。
这个N位索引随后用于访问一个128项的两位饱和计数器表(类似于cs450/counter_2bc)。计数器的值提供了预测(0或1表示不执行,2或3表示执行)。
训练方式类似地使用索引表。使用训练pc和历史计算表索引。然后,根据分支的实际结果,对该索引处的两位计数器进行增减。
参考文献
S. McFarling, "Combining Branch Predictors", WRL Technical Note TN-36, 1993年6月
描述
构建一个具有7位pc和7位全局历史的gshare分支预测器,通过异或运算散列成7位索引。这个索引访问一个128项的两位饱和计数器表(类似于第2小结cs450/counter_2bc)。分支预测器应包含一个7位的全局分支历史寄存器(类似于第3小结cs450/history_shift)。
分支预测器有两个接口集:一个用于进行预测,另一个用于训练。预测接口在处理器的取指阶段使用,向分支预测器询问正在获取的指令的分支方向预测。一旦这些分支继续下流水线并被执行,分支的真实结果就会被知晓。然后,根据实际的分支方向结果对分支预测器进行训练。
当请求对给定pc的分支进行预测(predict_valid = 1)时,分支预测器产生预测的分支方向和用于进行预测的分支历史寄存器状态。然后,在下一个正时钟边沿,分支历史寄存器会根据预测的分支进行更新。
当请求对分支进行训练(train_valid = 1)时,分支预测器会告知该分支的pc、用于训练的分支历 史寄存器值,以及分支的实际结果和是否为预测失误(需要流水线冲洗)。更新模式历史表(PHT),以便下次更准确地预测这个分支。此外,如果正在训练的分支预测失误,还要恢复分支历史寄存器到失误分支执行完成后的状态。
如果在同一个周期内,既发生了对预测失误的训练(针对一个更旧的指令),又进行了一个新的预测(针对一个不同的、更年轻的指令),这两种操作都会尝试修改分支历史寄存器。当这种情况发生时,训练操作具有优先级,因为即将被预测的分支无论如何都会被丢弃。如果对同一个PHT(Pattern History Table)条目的训练和预测同时发生,预测看到的是训练前的PHT状态,这是因为训练操作仅在下一个正时钟边沿才修改PHT。
下图显示了同时进行PHT条目0的训练和预测时的时间关系。在第4个周期的训练请求会在第5个周期改变PHT条目的状态,但是第4个周期的预测请求输出的是第4个周期的PHT状态,没有考虑到第4个周期训练请求的影响。
areset是一个异步复位,会将整个PHT清零为2b'01(弱不执行)。它还会将全局历史寄存器清零为0。
模块声明
module top_module(
input clk,
input areset,
input predict_valid,
input [6:0] predict_pc,
output predict_taken,
output [6:0] predict_history,
input train_valid,
input train_taken,
input train_mispredicted,
input [6:0] train_history,
input [6:0] train_pc
);